package net.csdn.business.mirror.service.impl;

import lombok.extern.slf4j.Slf4j;
import net.csdn.business.common.domain.PageDto;
import net.csdn.business.common.domain.common.ConditionQueryDto;
import net.csdn.business.common.domain.mirror.ProjectMirrorDataQueryDto;
import net.csdn.business.mirror.entity.bean.GithubToken;
import net.csdn.business.mirror.entity.bean.ProjectGithubData;
import net.csdn.business.mirror.entity.bean.ProjectMirrorData;
import net.csdn.business.mirror.entity.bean.ScheduleTask;
import net.csdn.business.mirror.enums.ProjectMirrorEnum;
import net.csdn.business.mirror.enums.UserTokenEnum;
import net.csdn.business.mirror.service.GithubTokenService;
import net.csdn.business.mirror.service.ProjectGithubDataService;
import net.csdn.business.mirror.service.ProjectMirrorDataService;
import net.csdn.business.mirror.service.ScheduleTaskImplement;
import net.csdn.business.mirror.utils.TimeUtil;
import org.kohsuke.github.GHRateLimit;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class ScheduleTaskSyncGithubImplement implements ScheduleTaskImplement {
    @Autowired
    private GithubTokenService githubTokenService;

    @Autowired
    private ProjectMirrorDataService projectMirrorDataService;

    @Autowired
    private ProjectGithubDataService projectGithubDataService;

    @Override
    public void exec(ScheduleTask scheduleTask) {
        Duration duration = TimeUtil.getCronDuration(scheduleTask.getCron());
        long minutes = duration.toMinutes();
        List<GithubToken> tokens = githubTokenService.getAllToken();
        Date now = new Date();
        int pageSize = 100;
        int currentCount = 100;
        while (currentCount >= pageSize) {
            ProjectMirrorDataQueryDto dto = new ProjectMirrorDataQueryDto();
            dto.setPageNum(1);
            dto.setPageSize(pageSize);
            dto.setOrder(new ConditionQueryDto.Order("next_sync_execution_at", true));
            dto.setStatusStr("1,3,4,6");
            dto.setIsSync(ProjectMirrorEnum.SyncStatus.OPEN.code); //查询启动镜像同步开关的镜像仓库配置信息
            dto.setType(UserTokenEnum.Type.GITHUB.getCode());
            dto.setUserType(ProjectMirrorEnum.UserType._0.code);
            dto.setSearchCount(false);
            dto.setNextSyncExecutionAt(now);
            PageDto<ProjectMirrorData> mirrorDataPaged = projectMirrorDataService.searchData(dto);
            List<ProjectMirrorData> list = mirrorDataPaged.getContent();
            currentCount = list.size();
            if (currentCount < 1) {
                return;
            }
            int r = sync(list, tokens, minutes);
            if (r == -1) {
                return;
            }
        }
    }

    public GitHub getGithubClient(List<GithubToken> tokens) {
        if (CollectionUtils.isEmpty(tokens)) {
            log.error("github token not exists");
            return null;
        }
        GitHub gitHub = null;
        String token = "";
        for (GithubToken githubToken : tokens) {
            try {
                token = githubToken.getToken();
                gitHub = new GitHubBuilder().withOAuthToken(token).build();
                GHRateLimit ghRateLimit = gitHub.getRateLimit();
                if (ghRateLimit.getCore().getRemaining() > 100) {
                    break;
                }
                gitHub = null;
            } catch (Exception e) {
                gitHub = null;
                log.error("get github client error token: {} message:{}", token, e.getMessage());
            }
        }
        return gitHub;
    }

    public int sync(List<ProjectMirrorData> dataList, List<GithubToken> tokens, long minutes) {
        for (ProjectMirrorData projectMirrorData : dataList) {
            int r = sync(projectMirrorData, tokens, minutes);
            if (r == -1) {
                return -1;
            }
        }
        return 2;
    }

    @Transactional(rollbackFor = Exception.class)
    public int sync(ProjectMirrorData data, List<GithubToken> tokens, long minutes) {
        GitHub gitHub = getGithubClient(tokens);
        if (Objects.isNull(gitHub)) {
            log.error("github client all invalid");
            return -1;
        }
        Date nextExecutionAt = TimeUtil.afterMins(data.getNextSyncExecutionAt(), minutes);
        Date now = new Date();
        if (nextExecutionAt.before(now)) {
            nextExecutionAt = now;
        }
        try {
            GHRepository ghRepository = gitHub.getRepository(data.getRepoPath());
            if (ghRepository == null) {
                projectMirrorDataService.updateSyncMirrorData(data.getId(), 4, nextExecutionAt, "");
                return 0;
            }
            projectMirrorDataService.updateSyncMirrorData(data.getId(), 3, nextExecutionAt, null);
            ProjectGithubData projectGithubData = ProjectGithubData.builder()
                    .starCount(ghRepository.getStargazersCount())
                    .forkCount(ghRepository.getForksCount())
                    .description(ghRepository.getDescription())
                    .mirrorId(data.getId())
                    .projectId(data.getProjectId())
                    .repoPath(data.getRepoPath())
                    .build();
//            JSONObject others = new JSONObject();
//            projectGithubData.setContent(JSON.toJSONString(others));
            projectGithubDataService.saveOrUpdateData(projectGithubData);
        } catch (Exception e) {
            projectMirrorDataService.updateSyncMirrorData(data.getId(), 4, nextExecutionAt, e.getMessage());
            return 0;
        }
        return 1;
    }


}